home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 4 / Apprentice-Release4.iso / Source Code / C++ / Frameworks / GameShell / Sourcery / GameShell.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1995-12-03  |  15.0 KB  |  539 lines  |  [TEXT/CWIE]

  1. #include <Palettes.h>
  2. #include <AppleEvents.h>
  3.  
  4. #include "GameShell.h"
  5. #include "assert_mac.h"
  6. #include "GameShellMonitor.h"
  7.  
  8. #include "Compat.h"
  9. #include "QDUtils.h"
  10. #include "GameUtils.h"
  11.  
  12. // ---------------------------------------------------------------------------
  13.  
  14. #define USE_GETNEXTEVENT
  15.  
  16. // ---------------------------------------------------------------------------
  17.  
  18. enum {
  19.     kMaxBlackoutWindows = 10,
  20.     
  21.     kAppleMenuID = 128
  22. };
  23.  
  24. typedef struct {
  25.     GDHandle    primaryDevice;
  26.     WindowPtr    mainWindow;
  27.     WindowPtr    backdropWindow;
  28.     WindowPtr    blackoutWindows[kMaxBlackoutWindows];
  29.     long        numBlackoutWindows;
  30.     
  31.     void        (*mainWindowUpdateFunction)();
  32.     void        (*menuHandlerFunction)(long);
  33.     void        (*mouseHandlerFunction)(CP_Point*);
  34.     void        (*keyHandlerFunction)(long);
  35.     void        (*idleHandlerFunction)();
  36.  
  37.     CP_Rect        windowBounds;
  38.     CP_Rect        windowSize;
  39.  
  40.     short        useMenuBar;                // true or false
  41.     short        useBlackout;            // true or false
  42.     short        useBackdrop;            // true or false
  43.     short        usingMainMonitor;        // true or false
  44.     short        primaryDeviceOrigDepth; // 1 to 32
  45.     short        _longwordPadding;
  46. } GameShellGlobals;
  47.  
  48. static GameShellGlobals sPrivateShellData;
  49. static long sGameShellQuitFlag;
  50.  
  51. // ---------------------------------------------------------------------------
  52.  
  53. static void GameShellHandleMouse(EventRecord *theEvent);
  54. static void GameShellHandleKeys(EventRecord *theEvent);
  55. static void GameShellHandleActivate(EventRecord *theEvent);
  56. static void GameShellHandleUpdate(EventRecord *theEvent);
  57.  
  58. static void GameShellHandleMenus(Point globalLoc);
  59. static void GameShellHandleIdle();
  60. static void GameShellHandleOSEvent(EventRecord *theEvent);
  61. static void GameShellHandleResume();
  62. static void GameShellHandleSuspend();
  63.  
  64. // ===========================================================================
  65.  
  66. CP_Window_Ref GameShellGetMainWindow()
  67. {
  68.     ASSERT(sPrivateShellData.mainWindow != NULL);
  69.     
  70.     return(sPrivateShellData.mainWindow);
  71. } // END GameShellGetMainWindow
  72.  
  73. // ---------------------------------------------------------------------------
  74.  
  75. CP_OutputDevice_Ref GameShellGetOutputDevice() {
  76.     ASSERT(sPrivateShellData.primaryDevice != NULL);
  77.     
  78.     return(sPrivateShellData.primaryDevice);
  79. } // END GameShellGetOutputDevice
  80.  
  81. // ---------------------------------------------------------------------------
  82.  
  83. void GameShellGetWindowCoords(CP_Rect *globCoords)
  84. {
  85.     ASSERT(!(globCoords == NULL));
  86.     
  87.     *globCoords = sPrivateShellData.windowBounds;
  88. } // END GameShellGetWindowCoords
  89.  
  90. // ---------------------------------------------------------------------------
  91.  
  92. void GameShellSetQuitFlag(long quitFlag) {
  93.     ASSERT(sGameShellQuitFlag == true || sGameShellQuitFlag == false);
  94.     
  95.     sGameShellQuitFlag = quitFlag;
  96. } // END GameShellSetQuitFlag
  97.  
  98. // ---------------------------------------------------------------------------
  99.  
  100. OSErr GameShellInitialize(UserParameters *userInfo)
  101. /*
  102.     Call this after initializing all your Mac toolbox routines, but
  103.     pretty much before calling anything else.
  104.     
  105.     GameShellInitialize will setup its internal variables, and then
  106.     setup the windows.
  107. */
  108. {
  109.     GDHandle curDevice;
  110.     long i;
  111.  
  112.     ASSERT(userInfo != NULL);
  113.  
  114.     CheckEnviron();
  115.  
  116.     SetRect(&sPrivateShellData.windowSize, 0, 0,
  117.         userInfo->windowWidth, userInfo->windowHeight);
  118.     
  119.     // The default is a call to GameShellChooseMonitor. You
  120.     // can change this to GameShellUserSelectMonitor if you wish.
  121.     sPrivateShellData.primaryDeviceOrigDepth = GameShellChooseMonitor(
  122.         &sPrivateShellData.primaryDevice, userInfo->preferredDepth,
  123.         userInfo->minimumDepth, userInfo->windowWidth, userInfo->windowHeight);
  124.     
  125.     // No monitors with preferred or minimum depths found!
  126.     if (sPrivateShellData.primaryDeviceOrigDepth == 0) {
  127.         return(1);
  128.     }
  129.     
  130.     // Handle menu bar hiding
  131.     ASSERT(!(userInfo->useMenuBar != true && userInfo->useMenuBar != false));
  132.     sPrivateShellData.useMenuBar = userInfo->useMenuBar;
  133.  
  134.     sPrivateShellData.usingMainMonitor = sPrivateShellData.primaryDevice ==
  135.         GetMainDevice();
  136.     HideMenuBar(false);
  137.  
  138.     // Handle menu bar initialization, if any
  139.     if (userInfo->useMenuBar && userInfo->menuInitFunction != NULL)
  140.         (*userInfo->menuInitFunction)();
  141.     sPrivateShellData.menuHandlerFunction = userInfo->menuHandlerFunction;
  142.  
  143.     // Handle blacking out of other windows
  144.     ASSERT(!(userInfo->useBlackout != true && userInfo->useBlackout != false));
  145.     sPrivateShellData.useBlackout = userInfo->useBlackout;
  146.  
  147.     for (i = 0; i < kMaxBlackoutWindows; i++)
  148.         sPrivateShellData.blackoutWindows[i] = NULL;
  149.  
  150.     sPrivateShellData.numBlackoutWindows = 0;
  151.  
  152.     if (sPrivateShellData.useBlackout == true) {
  153.         curDevice = GetDeviceList();
  154.  
  155.         while (curDevice != NULL &&
  156.             sPrivateShellData.numBlackoutWindows < kMaxBlackoutWindows) {
  157.                 // No blackout windows for primary monitor; it'll
  158.                 // be handled by both backdrop and main window
  159.             if (curDevice != sPrivateShellData.primaryDevice) {
  160.  
  161.                 sPrivateShellData.blackoutWindows[sPrivateShellData.numBlackoutWindows] =
  162.                     NewCWindow(NULL, &(**curDevice).gdRect, "\p", true,
  163.                     plainDBox, (WindowPtr)-1, false, sPrivateShellData.numBlackoutWindows);
  164.                 ASSERT(!(sPrivateShellData.blackoutWindows[sPrivateShellData.numBlackoutWindows]==NULL));
  165.     
  166.                 SetPort(sPrivateShellData.blackoutWindows[sPrivateShellData.numBlackoutWindows]);
  167.                 FillRect(&sPrivateShellData.blackoutWindows[sPrivateShellData.numBlackoutWindows]->portRect,
  168.                     &qd.black);
  169.     
  170.                 sPrivateShellData.numBlackoutWindows++;
  171.             }
  172.  
  173.             curDevice = GetNextDevice(curDevice);
  174.         }
  175.     }
  176.  
  177.     // Handle backdrop window
  178.     ASSERT(!(userInfo->useBackdrop != true && userInfo->useBackdrop != false));
  179.     sPrivateShellData.useBackdrop = userInfo->useBackdrop;
  180.     sPrivateShellData.backdropWindow = NULL;
  181.  
  182.     // Handle only if monitor is larger than main window (thus showing desktop).
  183.     // If main window is the same size as the monitor, there's no need for a
  184.     // backdrop window.
  185.     if ((sPrivateShellData.useBackdrop) &&
  186.         ((((**sPrivateShellData.primaryDevice).gdRect.right -
  187.             (**sPrivateShellData.primaryDevice).gdRect.left) > userInfo->windowWidth)
  188.            && (((**sPrivateShellData.primaryDevice).gdRect.bottom -
  189.            (**sPrivateShellData.primaryDevice).gdRect.top) > userInfo->windowHeight))) {
  190.  
  191.         sPrivateShellData.backdropWindow = NewCWindow(NULL,
  192.             &(**sPrivateShellData.primaryDevice).gdRect, "\p", true,
  193.             plainDBox, (WindowPtr)-1, false, 0);
  194.         ASSERT(!(sPrivateShellData.backdropWindow == NULL));
  195.         
  196.         SetPort(sPrivateShellData.backdropWindow);
  197.         FillRect(&sPrivateShellData.backdropWindow->portRect, &qd.black);
  198.     }
  199.  
  200.     // Handle main window
  201.     sPrivateShellData.windowBounds = sPrivateShellData.windowSize;
  202.     CenterRect(&sPrivateShellData.windowBounds,
  203.         &(**sPrivateShellData.primaryDevice).gdRect);
  204.     sPrivateShellData.mainWindow = NULL;
  205.     sPrivateShellData.mainWindow = NewCWindow(NULL, &sPrivateShellData.windowBounds,
  206.         "\p", true, plainDBox, (WindowPtr)-1, false, 0);
  207.     ASSERT(!(sPrivateShellData.mainWindow == NULL));
  208.     
  209.     SetPort(sPrivateShellData.mainWindow);
  210.     FillRect(&sPrivateShellData.mainWindow->portRect, &qd.black);
  211.     
  212.     // The main window updater & mouse handler functions are MANDATORY.
  213.     // You must supply them.
  214.     ASSERT(!(userInfo->mainWindowUpdateFunction == NULL));
  215.     sPrivateShellData.mainWindowUpdateFunction = userInfo->mainWindowUpdateFunction;
  216.     ASSERT(!(userInfo->mouseHandlerFunction == NULL));
  217.     sPrivateShellData.mouseHandlerFunction = userInfo->mouseHandlerFunction;
  218.  
  219.     // These are optional
  220.     sPrivateShellData.keyHandlerFunction = userInfo->keyHandlerFunction;
  221.     sPrivateShellData.idleHandlerFunction = userInfo->idleHandlerFunction;
  222.  
  223.     sGameShellQuitFlag = false;
  224.  
  225.     return(noErr);
  226. } // END GameShellInitialize
  227.  
  228. // ---------------------------------------------------------------------------
  229.  
  230. void GameShellCleanup()
  231. {
  232.     // Restore menu bar if necessary
  233.     ShowMenuBar();
  234.     
  235.     // Restore depth if necessary
  236.     if ((**(**sPrivateShellData.primaryDevice).gdPMap).pixelSize !=
  237.         sPrivateShellData.primaryDeviceOrigDepth)
  238.         SetDepth(sPrivateShellData.primaryDevice,
  239.             sPrivateShellData.primaryDeviceOrigDepth, 1 << gdDevType, 1);
  240. } // END GameShellCleanup
  241.  
  242. // ---------------------------------------------------------------------------
  243.  
  244. void GameShellLoop()
  245. {
  246.     EventRecord theEvent;
  247.     short eventExists;
  248.     short padding;
  249.  
  250.     while (!sGameShellQuitFlag) {
  251.  
  252. #ifdef USE_GETNEXTEVENT
  253.         eventExists = GetNextEvent(everyEvent, &theEvent);
  254. #else
  255.         eventExists = WaitNextEvent(everyEvent, &theEvent, 2, NULL);
  256. #endif
  257.  
  258.         if (eventExists) {
  259.             switch(theEvent.what) {
  260.                 case mouseDown: //case mouseUp:
  261.                     GameShellHandleMouse(&theEvent);
  262.                 break;
  263.                 
  264.                 case keyDown: case keyUp:
  265.                     GameShellHandleKeys(&theEvent);
  266.                 break;
  267.                 
  268.                 case activateEvt:
  269.                     GameShellHandleActivate(&theEvent);
  270.                 break;
  271.                 
  272.                 case updateEvt:
  273.                     GameShellHandleUpdate(&theEvent);
  274.                 break;
  275.                 
  276.                 case osEvt:
  277.                     GameShellHandleOSEvent(&theEvent);
  278.                 break;
  279.                 
  280.                 case kHighLevelEvent:
  281.                 break;
  282.             }
  283.         }
  284.         else {
  285.             // Handle idleness
  286.             GameShellHandleIdle();
  287.         }
  288.     }
  289. } // END GameShellLoop
  290.  
  291. // ---------------------------------------------------------------------------
  292.  
  293. void GameShellHandleMouse(EventRecord *theEvent)
  294. /*
  295.     This routine handles mouse clicks in the menu bar area (if menus
  296.     are used) and in the main window's content area. All others are
  297.     ignored.
  298. */
  299. {
  300.     Rect menuBarRect;
  301.  
  302.     WindowPtr theWindow;
  303.     short thePart;
  304.  
  305.     ASSERT(theEvent != NULL);
  306.     
  307.     thePart = FindWindow(theEvent->where, &theWindow);
  308.     switch(thePart) {
  309.         case inMenuBar:
  310.             // If we're invoked, we assume that the menu bar's visible.
  311.             if (sPrivateShellData.useMenuBar &&
  312.                 sPrivateShellData.menuHandlerFunction != NULL) {
  313.                 GameShellHandleMenus(theEvent->where);
  314.             }
  315.         break;
  316.         
  317.         case inContent:
  318.             // Kind of tricky here. We also have to handle the menu bar...
  319.             
  320.             // Show menu bar ONLY if it's currently hidden AND
  321.             // the user clicks in the area normally occupied by the menu bar.
  322.             if (sPrivateShellData.useMenuBar && gMenuBarHidden) {
  323.                 GetMenuBarRect(&menuBarRect);
  324.                 if (PtInRect(theEvent->where, &menuBarRect))
  325.                     ShowMenuBar();
  326.             }
  327.             
  328.             // User clicks in main window; call mouse handler.
  329.             if (theWindow == sPrivateShellData.mainWindow) {
  330.                 SetPort(sPrivateShellData.mainWindow);
  331.                 GlobalToLocal(&theEvent->where);
  332.                 (*sPrivateShellData.mouseHandlerFunction)((CP_Point*)&theEvent->where);
  333.             }
  334.         break;
  335.     }
  336. } // END GameShellHandleMouse
  337.  
  338. // ---------------------------------------------------------------------------
  339.  
  340. void GameShellHandleKeys(EventRecord *theEvent)
  341. {
  342.     char theChar;
  343.     char pad1, pad2, pad3;
  344.  
  345.     ASSERT(theEvent != NULL);
  346.     
  347.     theChar = theEvent->message & charCodeMask;
  348.     // Call keydown handler if one is provided.
  349.     if (sPrivateShellData.keyHandlerFunction != NULL)
  350.         (*sPrivateShellData.keyHandlerFunction)((long)theChar);
  351.     else {
  352.         sGameShellQuitFlag = true;
  353.     }
  354. } // END GameShellHandleKeys
  355.  
  356. // ---------------------------------------------------------------------------
  357.  
  358. void GameShellHandleActivate(EventRecord *theEvent)
  359. {
  360.     WindowPtr theWindow;
  361.  
  362.     ASSERT(theEvent != NULL);
  363.     
  364.     theWindow = (WindowPtr)theEvent->message;
  365.     ASSERT(!(theWindow == NULL));
  366.  
  367.     if (theEvent->modifiers & activeFlag != 0) {
  368.         // Activate event
  369.         SetPort(theWindow);
  370.     }
  371.     else {
  372.         // Deactivate event
  373.     }
  374. } // END GameShellHandleActivate
  375.  
  376. // ---------------------------------------------------------------------------
  377.  
  378. void GameShellHandleUpdate(EventRecord *theEvent)
  379. {
  380.     GrafPtr savePort;
  381.     WindowPtr theWindow;
  382.  
  383.     ASSERT(theEvent != NULL);
  384.     
  385.     theWindow = (WindowPtr)theEvent->message;
  386.     ASSERT(theWindow != NULL);
  387.  
  388.     GetPort(&savePort);
  389.     SetPort(theWindow);
  390.  
  391.     BeginUpdate(theWindow);
  392.  
  393.     if (theWindow == sPrivateShellData.mainWindow)
  394.         (*sPrivateShellData.mainWindowUpdateFunction)();
  395.     else {
  396.         SetPort(theWindow);
  397.         FillRect(&theWindow->portRect, &qd.black);
  398.         SetPort(sPrivateShellData.mainWindow);
  399.     }
  400.  
  401.     EndUpdate(theWindow);
  402.     
  403.     SetPort(savePort);
  404. } // END GameShellHandleUpdate
  405.  
  406. // ---------------------------------------------------------------------------
  407.  
  408. void GameShellHandleMenus(Point globalLoc)
  409. /*
  410.     The user is expected to handle all menus and menu items
  411.     except for those desk accessories and other junk in the
  412.     Apple menu; we'll handle it for them (note the user still
  413.     has to handle the About... item in the Apple Menu).
  414. */
  415. {
  416.     long menuCode;
  417.     short menuData;
  418.     short padding;
  419.     Str255 daName;
  420.  
  421.     menuCode = MenuSelect(globalLoc);
  422.     if (menuCode == 0) return;
  423.  
  424.     // Yeah, unhilite it *now*. The menu handler function is
  425.     // not expected to have to deal with this extraneous crap.
  426.     HiliteMenu(0);
  427.  
  428.     // Menu bar has to be visible before getting an
  429.     // inMenuBar mouse click, so we know it's visible...
  430.     // Hide menu bar before calling menu item handler.
  431.     if (!gMenuBarHidden)
  432.         HideMenuBar(false);
  433.  
  434.     menuData = HiWord(menuCode);
  435.  
  436.     if (menuData == kAppleMenuID) {
  437.         menuData = LoWord(menuCode);
  438.         if (menuData > 1) {
  439.             GetMenuItemText(GetMenuHandle(kAppleMenuID), menuData,
  440.                 daName);
  441.             (void)OpenDeskAcc(daName);
  442.         }
  443.         else
  444.             (*sPrivateShellData.menuHandlerFunction)(menuCode);
  445.     }
  446.     else
  447.         (*sPrivateShellData.menuHandlerFunction)(menuCode);
  448. } // END GameShellHandleMenus
  449.  
  450. // ---------------------------------------------------------------------------
  451.  
  452. void GameShellHandleIdle()
  453. {
  454.     Rect menuBarRect;
  455.     Point mouseLoc;
  456.  
  457.     // Hide menu bar if currently shown and mouse not
  458.     // in menu bar area.
  459.     if (sPrivateShellData.useMenuBar && !gMenuBarHidden) {
  460.         GetMenuBarRect(&menuBarRect);
  461.         GetMouse(&mouseLoc);
  462.         LocalToGlobal(&mouseLoc);
  463.         if (!PtInRect(mouseLoc, &menuBarRect))
  464.             HideMenuBar(false);
  465.     }
  466.     
  467.     if (sPrivateShellData.idleHandlerFunction != NULL)
  468.         (*sPrivateShellData.idleHandlerFunction)();
  469. } // END GameShellHandleIdle
  470.  
  471. // ---------------------------------------------------------------------------
  472.  
  473. void GameShellHandleOSEvent(EventRecord *theEvent)
  474. {
  475.     ASSERT(!(theEvent == NULL));
  476.  
  477.     if (((theEvent->message >> 24) & 0x0FF) == suspendResumeMessage) {
  478.         if (theEvent->message & resumeFlag != 0) {
  479.             // Resume event
  480.             GameShellHandleResume();
  481.         }
  482.         else {
  483.             // Suspend event
  484.             GameShellHandleSuspend();
  485.         }
  486.     }
  487. } // END GameShellHandleOSEvent
  488.  
  489. // ---------------------------------------------------------------------------
  490.  
  491. void GameShellHandleResume()
  492. {
  493.     long i;
  494.  
  495.     // Show all windows; do the blackout windows first, if any
  496.     if (sPrivateShellData.useBlackout) {
  497.         for (i = 0; i < sPrivateShellData.numBlackoutWindows; i++) {
  498.             ASSERT(sPrivateShellData.blackoutWindows[i] != NULL);
  499.             ShowWindow(sPrivateShellData.blackoutWindows[i]);
  500.         }
  501.     }
  502.     
  503.     // Do backdrop
  504.     if (sPrivateShellData.useBackdrop &&
  505.         sPrivateShellData.backdropWindow != NULL)
  506.         ShowWindow(sPrivateShellData.backdropWindow);
  507.     
  508.     ShowWindow(sPrivateShellData.mainWindow);
  509.     SelectWindow(sPrivateShellData.mainWindow);
  510.     SetPort(sPrivateShellData.mainWindow);
  511.     
  512.     HideMenuBar(false);
  513. } // END GameShellHandleResume
  514.  
  515. // ---------------------------------------------------------------------------
  516.  
  517. void GameShellHandleSuspend()
  518. {
  519.     long i;
  520.  
  521.     // Hide all windows; first do the blackout windows
  522.     if (sPrivateShellData.useBlackout) {
  523.         for (i = 0; i < sPrivateShellData.numBlackoutWindows; i++) {
  524.             ASSERT(sPrivateShellData.blackoutWindows[i] != NULL);
  525.             HideWindow(sPrivateShellData.blackoutWindows[i]);
  526.         }
  527.     }
  528.     
  529.     // Now do backdrop, if any
  530.     if (sPrivateShellData.useBackdrop &&
  531.         sPrivateShellData.backdropWindow != NULL) {
  532.         HideWindow(sPrivateShellData.backdropWindow);
  533.     }
  534.     
  535.     // Now do main window
  536.     HideWindow(sPrivateShellData.mainWindow);
  537.     
  538.     ShowMenuBar();
  539. } // END GameShellHandleSuspend